/***********************************************************
 *  File_Name  : XJJsonBase.cpp
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : Json序列化基类
 *
 *  OS : Linux, UNIX
 *  LastVersion  : 20240213
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2024-2-13
 *  Version     : 20240213
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 ***********************************************************/
#include "XJJsonBase.h"

namespace XJUtilClass
{
#define GetJsonObjItemToStr(cjson, value)                 \
    {                                                     \
        cJSON *item = cJSON_GetObjectItem(cjson, #value); \
        if (item && item->type == cJSON_String)           \
        {                                                 \
            value = item->valuestring;                    \
        }                                                 \
    }
#define GetJsonObjItemToInt(cjson, value)                 \
    {                                                     \
        cJSON *item = cJSON_GetObjectItem(cjson, #value); \
        if (item && item->type == cJSON_Number)           \
        {                                                 \
            value = static_cast<int>(item->valuedouble);  \
        }                                                 \
    }
#define GetJsonObjItemToFloat(cjson, value)                \
    {                                                      \
        cJSON *item = cJSON_GetObjectItem(cjson, #value);  \
        if (item && item->type == cJSON_Number)            \
        {                                                  \
            value = static_cast<float>(item->valuedouble); \
        }                                                  \
    }

#define GetJsonObjItemToStr2(cjson, name, value)        \
    {                                                   \
        cJSON *item = cJSON_GetObjectItem(cjson, name); \
        if (item && item->type == cJSON_String)         \
        {                                               \
            value = item->valuestring;                  \
        }                                               \
    }

    XJJsonField::XJJsonField() : _type(XJJFT_STRING), _value(NULL), _val_type(NULL)
    {
        // printf("XJJsonField %p \n", _val_type);
    }
    XJJsonField::XJJsonField(const std::string &name, const int type, void *value, XJJsonBase *val_type) : _name(name), _type(type), _value(value), _val_type(val_type)
    {
        // printf("XJJsonField %p \n", _val_type);
    }
    XJJsonField::~XJJsonField()
    {
        // printf("_val_type %p \n", _val_type);
        if (_val_type != NULL)
        {
            delete _val_type;
            _val_type = NULL;
        }
    }
    bool XJJsonBase::UseUTF8 = true;
    XJJsonBase::XJJsonBase()
    {
    }
    XJJsonBase::~XJJsonBase()
    {
        std::list<XJJsonField *>::iterator it = _bind_map.begin();
        for (; it != _bind_map.end(); ++it)
        {
            XJJsonField *field = *it;
            delete field;
            field = NULL;
        }
        _bind_map.clear();
    }

    cJSON *XJJsonBase::PackObj() const
    {
        cJSON *cjson = cJSON_CreateObject();
        if (NULL == cjson)
        {
            printf("Error: XJJsonBase::PackObj cJSON_CreateObject is null.\n");
            return NULL;
        }
        std::list<XJJsonField *>::const_iterator it = _bind_map.begin();
        // cout << "XJJsonBase::PackObj _bind_map.size" << _bind_map.size() << endl;
        for (; it != _bind_map.end(); ++it)
        {
            XJJsonField *pField = *it;
            const char *f_name = pField->_name.c_str();
            // cout << "XJJsonBase::PackObj f_name" << f_name << endl;
            int f_type = pField->_type;
            void *f_value = pField->_value;

            // void* f_vtype = (void*)(pField->_val_type);
            if (f_type == XJJFT_STRING)
            {
                cJSON_AddStringToObject(cjson, f_name, ((std::string *)(f_value))->c_str());
            }
            else if (f_type == XJJFT_UINT16)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(uint16_t *)(f_value)));
            }
            else if (f_type == XJJFT_UINT32)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(uint32_t *)(f_value)));
            }
            else if (f_type == XJJFT_UINT64)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(uint64_t *)(f_value)));
            }
            else if (f_type == XJJFT_INT16)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(int16_t *)(f_value)));
            }
            else if (f_type == XJJFT_INT32)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(int32_t *)(f_value)));
            }
            else if (f_type == XJJFT_INT64)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(int64_t *)(f_value)));
            }
            else if (f_type == XJJFT_FLOAT)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(float *)(f_value)));
            }
            else if (f_type == XJJFT_DOUBLE)
            {
                cJSON_AddNumberToObject(cjson, f_name, (*(double *)(f_value)));
            }
            else if (f_type == XJJFT_OBJ)
            {
                cJSON_AddItemToObject(cjson, f_name,
                                      ((XJJsonBase *)(f_value))->PackObj());
            }
            else if (f_type == XJJFT_LIST_OBJ)
            {
                std::list<XJJsonBase *> *pList = (std::list<XJJsonBase *> *)(f_value);

                std::list<XJJsonBase *>::iterator it2 = pList->begin();
                cJSON *cjarr = cJSON_CreateArray();
                for (; it2 != pList->end(); ++it2)
                {
                    XJJsonBase *base = (XJJsonBase *)*it2;
                    cJSON_AddItemToArray(cjarr, (base)->PackObj());
                }
                cJSON_AddItemToObject(cjson, f_name, cjarr);
            }
            else if (f_type == XJJFT_LIST_STR)
            {
                std::list<std::string>::iterator it2 = (*(std::list<std::string> *)(f_value)).begin();
                cJSON *cjarr = cJSON_CreateArray();
                for (; it2 != (*(std::list<std::string> *)(f_value)).end(); ++it2)
                {
                    cJSON_AddItemToArray(cjarr, cJSON_CreateString(it2->c_str()));
                }
                cJSON_AddItemToObject(cjson, f_name, cjarr);
            }
        }
        return cjson;
    }

    // 返回值 XJJ_RET_OK 成功, 其他失败
    int XJJsonBase::UnPack(cJSON *cjson)
    {
        int ret = 0;
        if (NULL == cjson)
        {
            return XJJ_RET_ERR;
        }
        std::list<XJJsonField *>::iterator it = _bind_map.begin();
        for (; it != _bind_map.end(); ++it)
        {
            XJJsonField *pField = *it;
            const char *f_name = pField->_name.c_str();
            void *f_value = pField->_value;
            void *f_vtype = pField->_val_type;
            int f_type = pField->_type;
            cJSON *item = cJSON_GetObjectItem(cjson, f_name);
            if (item == NULL)
            {
                // printf("Error: JSON UnPack failed, item is null. json_key:%s, json_type:%d, field_type:%d, ret:%d\n",
                //             f_name, (item?item->type:-1), f_type, ret);
                continue;
            }
            if (f_type == XJJFT_STRING)
            {
                if (item && (item->type == cJSON_String || item->type == cJSON_Raw))
                {
                    if (item->valuestring != NULL)
                    {
                        *(std::string *)f_value = item->valuestring;
                        // printf("Debug: JSON UnPack success. json_key:%s, json_type:%d, field_type:%d, ret:%d, val:%x\n",
                        //     f_name, (item?item->type:-1), f_type, ret, item->valuestring);
                    }
                    else
                    {
                        printf("Error: JSON UnPack failed. json_key:%s, json_type:%d, field_type:%d, ret:%d\n",
                               f_name, (item ? item->type : -1), f_type, ret);
                    }
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_UINT16)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(uint16_t *)(f_value)) = static_cast<uint16_t>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_UINT32)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(uint32_t *)(f_value)) = static_cast<uint32_t>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_UINT64)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(uint64_t *)(f_value)) = static_cast<uint64_t>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_INT16)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(int16_t *)(f_value)) = static_cast<int16_t>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_INT32)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(int32_t *)(f_value)) = static_cast<int32_t>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_INT64)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(int64_t *)(f_value)) = static_cast<int64_t>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_FLOAT)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(float *)(f_value)) = static_cast<float>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_DOUBLE)
            {
                if (item && item->type == cJSON_Number)
                {
                    (*(double *)(f_value)) = static_cast<double>(item->valuedouble);
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_OBJ)
            {
                if (item && item->type == cJSON_Object)
                {
                    ret = ((XJJsonBase *)(f_value))->UnPack(item);
                    if (ret != 0)
                    {
                        printf("Error: JSON UnPack failed. json_key:%s, json_type:%d, field_type:%d, ret:%d\n",
                               f_name, (item ? item->type : -1), f_type, ret);
                    }
                    else
                    {
                        // printf("Debug:  JSON UnPack success. json_key:%s, json_type:%d, field_type:%d, ret:%d, val:%x\n",
                        //     f_name, (item?item->type:-1), f_type, ret, (item?item->child:0));
                    }
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_LIST_OBJ)
            {
                if (item && item->type == cJSON_Array)
                {
                    int arrSize = cJSON_GetArraySize(item);
                    for (int i = 0; i < arrSize; i++)
                    {
                        XJJsonBase *itemObj = ((XJJsonBase *)f_vtype)->New();
                        if (0 == itemObj->UnPack(cJSON_GetArrayItem(item, i)))
                        {
                            ((std::list<XJJsonBase *> *)f_value)->push_back(itemObj);
                        }
                        else
                        {
                            delete itemObj;
                        }
                    }
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
            else if (f_type == XJJFT_LIST_STR)
            {
                if (item && item->type == cJSON_Array)
                {
                    int arrSize = cJSON_GetArraySize(item);
                    for (int i = 0; i < arrSize; i++)
                    {
                        cJSON *cjsonstr = cJSON_GetArrayItem(item, i);
                        if (cJSON_String == cjsonstr->type || cJSON_Raw == cjsonstr->type)
                        {
                            ((std::list<std::string> *)f_value)->push_back(cjsonstr->valuestring);
                        }
                    }
                }
                else
                {
                    printf("Error: Invalid JSON Type. json_key:%s, json_type:%d, field_type:%d\n",
                           f_name, (item ? item->type : -1), f_type);
                }
            }
        }
        return XJJ_RET_OK;
    }

    std::string XJJsonBase::Pack() const
    {
        std::string buf;
        cJSON *cjson = PackObj();
        if (NULL == cjson)
        {
            return buf;
        }
        char *str = cJSON_PrintUnformatted(cjson);
        if (str != NULL)
        {
            buf.append(str);
            cJSON_free(str);
            str = NULL;
        }
        cJSON_Delete(cjson);
        return buf;
    }

    // 返回值: 小于0:失败;大于等于0:已解析索引
    int XJJsonBase::UnPack(uint8_t *data, int index, int count)
    {
        cJSON *cjson = cJSON_Parse((char *)data + index);
        if (NULL == cjson)
        {
            return XJJ_RET_ERR;
        }
        int ret = UnPack(cjson);
        cJSON_Delete(cjson);
        if (XJJ_RET_OK != ret)
        {
            return ret;
        }
        return index + count;
    }
    // 返回值: 小于0:失败;大于等于0:已解析索引
    int XJJsonBase::UnPack(std::string data)
    {
        return UnPack((uint8_t *)data.data(), 0, data.size());
    }

} // XJUtilClass